﻿using System;
using System.Diagnostics;

namespace Tables
{
	[Serializable]
	class StringTable : IDisposable
	{
		public StringTable ()
            : this(100)
		{
		}

		public StringTable (int maxStrings)
		{
			_curId = 0;
			_maxStrings = maxStrings;
			_offset = new int[maxStrings];
			_strBuf = new StringBuffer (maxStrings);
			_htab = new HTable (maxStrings);
		}
		/// <summary>
		/// Adds with out checking for duplicates
		/// </summary>
		/// <param name="str"></param>
		/// <param name="len"></param>
		/// <returns></returns>
		public int ForceAdd (string str, int len)
		{
			// check if there is enough room in the array
			if (_curId == _maxStrings || !_strBuf.WillFit (len)) {
				return idNotFound;
			}
			// point to the place where the string is stored
			_offset [_curId] = _strBuf.GetOffset ();
			_strBuf.Add (str);
			// add mapping into hash table
			_htab.Add (str, _curId);
			++_curId;
			return _curId - 1;
		}
		/// <summary>
		/// Adds with out checking for duplicates
		/// </summary>
		/// <param name="str"></param>
		/// <returns></returns>
		public int ForceAdd (string str)
		{
			return ForceAdd (str, str.Length);
		}
		/// <summary>
		/// Translates a string into an id value
		/// </summary>
		/// <param name="str"></param>
		/// <returns></returns>
		public int Find (string str)
		{
			// get short list from hash table
			List list = _htab.Find (str);
			// iterate list
			for (Link pLink = list.GetHead();
                list.Count != 0;
                pLink = pLink.Next()) {
				int id = pLink.Id ();
				int offset = _offset [id];
				if (_strBuf.IsEqual (offset, str))
					return id;
			}
			return idNotFound;
		}
		/// <summary>
		/// uses an id value and returns the string for it
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public string GetString (int id)
		{
			// map integer to string, must be valid id
			Debug.Assert (id >= 0);
			Debug.Assert (id < _curId);
			int offset = _offset [id];
			return _strBuf.GetString (offset);
		}

		public void Dispose ()
		{
			Dispose (true);
			GC.SuppressFinalize (this);
		}

		protected virtual void Dispose (bool disposing)
		{
			if (!_disposed) {
				if (disposing) {
					//disposed managed resource

				}
				// release unmanaged resource
			}
			_disposed = true;

			// if available, call to base class
			// base.Dispose(disposing);
		}

		private HTable _htab;
		private int[] _offset;
		private int _curId;
		private StringBuffer _strBuf;
		private bool _disposed = false;
		private const int idNotFound = -1;
		private int _maxStrings;
	}
}
